package com.lineage.server.model.map;

import com.lineage.server.model.Instance.L1DoorInstance;
import com.lineage.server.model.Instance.L1NpcInstance;
import com.lineage.server.model.L1Character;
import com.lineage.server.model.L1Object;
import com.lineage.server.types.Point;
import com.lineage.server.world.World;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class L1V1Map extends L1Map {
  private static final Log _log = LogFactory.getLog(L1V1Map.class);
  
  private static final byte BITFLAG_IS_IMPASSABLE = -128;
  
	// 正向
	private static final byte HEADING_TABLE_X[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
	private static final byte HEADING_TABLE_Y[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
  
  private int _mapId;
  
  private int _worldTopLeftX;
  
  private int _worldTopLeftY;
  
  private int _worldBottomRightX;
  
  private int _worldBottomRightY;
  
  private byte[][] _map;
  
  private boolean _isUnderwater;
  
  private boolean _isMarkable;
  
  private boolean _isTeleportable;
  
  private boolean _isEscapable;
  
  private boolean _isUseResurrection;
  
  private boolean _isUsePainwand;
  
  private boolean _isEnabledDeathPenalty;
  
  private boolean _isTakePets;
  
  private boolean _isRecallPets;
  
  private boolean _isUsableItem;
  
  private boolean _isUsableSkill;
  
  private boolean _isGuaji;
  
  private boolean _isClanPc;
  
  private boolean _isPartyPc;
  
  private boolean _isAlliancePc;
  
  private boolean _isdropitem;
  
  private int _isUsableShop;
  
  private int _isStart_time;
  
  private int _isEnd_time;
  
  private int _isweek;
  
  protected L1V1Map() {}
  
  public L1V1Map(int mapId, byte[][] map, int worldTopLeftX, int worldTopLeftY, boolean underwater, boolean markable, boolean teleportable, boolean escapable, boolean useResurrection, boolean usePainwand, boolean enabledDeathPenalty, boolean takePets, boolean recallPets, boolean usableItem, boolean usableSkill, boolean Guaji, boolean isClanPc, boolean isPartyPc, boolean isAlliancePc, boolean isdropitem, int usableShop, int Start_time, int End_time, int week) {
    this._mapId = mapId;
    this._map = map;
    this._worldTopLeftX = worldTopLeftX;
    this._worldTopLeftY = worldTopLeftY;
    this._worldBottomRightX = worldTopLeftX + map.length - 1;
    this._worldBottomRightY = worldTopLeftY + (map[0]).length - 1;
    this._isUnderwater = underwater;
    this._isMarkable = markable;
    this._isTeleportable = teleportable;
    this._isEscapable = escapable;
    this._isUseResurrection = useResurrection;
    this._isUsePainwand = usePainwand;
    this._isEnabledDeathPenalty = enabledDeathPenalty;
    this._isTakePets = takePets;
    this._isRecallPets = recallPets;
    this._isUsableItem = usableItem;
    this._isUsableSkill = usableSkill;
    this._isGuaji = Guaji;
    this._isClanPc = isClanPc;
    this._isPartyPc = isPartyPc;
    this._isAlliancePc = isAlliancePc;
    this._isdropitem = isdropitem;
    this._isUsableShop = usableShop;
    this._isStart_time = Start_time;
    this._isEnd_time = End_time;
    this._isweek = week;
  }
  
  public L1V1Map(L1V1Map map) {
    this._mapId = map._mapId;
    this._map = new byte[map._map.length][];
    int i = 0;
    while (i < map._map.length) {
      this._map[i] = (byte[])map._map[i].clone();
      i++;
    } 
    this._worldTopLeftX = map._worldTopLeftX;
    this._worldTopLeftY = map._worldTopLeftY;
    this._worldBottomRightX = map._worldBottomRightX;
    this._worldBottomRightY = map._worldBottomRightY;
  }
  
  public void setTestTile(int x, int y, int tile) {
    setTile(x, y, tile);
  }
  
  private int accessTile(int x, int y) {
    if (!isInMap(x, y))
      return 0; 
    return this._map[x - this._worldTopLeftX][y - this._worldTopLeftY];
  }
  
  private int accessOriginalTile(int x, int y) {
    return accessTile(x, y) & 0x7F;
  }
  
  public void setTile(int x, int y, int tile) {
    if (!isInMap(x, y))
      return; 
    this._map[x - this._worldTopLeftX][y - this._worldTopLeftY] = (byte)tile;
  }
  
  public byte[][] getRawTiles() {
    return this._map;
  }
  
  public int getId() {
    return this._mapId;
  }
  
  public int getX() {
    return this._worldTopLeftX;
  }
  
  public int getY() {
    return this._worldTopLeftY;
  }
  
  public int getWidth() {
    return this._worldBottomRightX - this._worldTopLeftX + 1;
  }
  
  public int getHeight() {
    return this._worldBottomRightY - this._worldTopLeftY + 1;
  }
  
  public int getTile(int x, int y) {
    short tile = this._map[x - this._worldTopLeftX][y - this._worldTopLeftY];
    if ((tile & 0xFFFFFF80) != 0)
      return 300; 
    return accessOriginalTile(x, y);
  }
  
  public int getOriginalTile(int x, int y) {
    return accessOriginalTile(x, y);
  }
  
  public boolean isInMap(Point pt) {
    return isInMap(pt.getX(), pt.getY());
  }
  
  public boolean isInMap(int x, int y) {
    return ((this._mapId != 4 || (x >= 32520 && y >= 32070 && (y >= 32190 || x >= 33950))) && 
      this._worldTopLeftX <= x && x <= this._worldBottomRightX && this._worldTopLeftY <= y && 
      y <= this._worldBottomRightY);
  }
  
  public boolean isPassable(int x, int y) {
    return !(!isPassable(x, y - 1, 4) && !isPassable(x + 1, y, 6) && !isPassable(x, y + 1, 0) && 
      !isPassable(x - 1, y, 2));
  }
  
  public boolean isPassable(Point pt, L1Character cha) {
    return isPassable(pt.getX(), pt.getY(), cha);
  }
  
  public boolean isPassable(int x, int y, L1Character cha) {
    return !(!isPassable(x, y - 1, 4, cha) && !isPassable(x + 1, y, 6, cha) && 
      !isPassable(x, y + 1, 0, cha) && !isPassable(x - 1, y, 2, cha));
  }
  
  public boolean isPassable(Point pt, int heading, L1Character cha) {
    return isPassable(pt.getX(), pt.getY(), heading, cha);
  }
  
  public boolean isPassable(int x, int y, int heading) {
    int tile2, newX, newY, tile1 = accessTile(x, y);
    if (heading == 0) {
      tile2 = accessTile(x, y - 1);
      newX = x;
      newY = y - 1;
    } else if (heading == 1) {
      tile2 = accessTile(x + 1, y - 1);
      newX = x + 1;
      newY = y - 1;
    } else if (heading == 2) {
      tile2 = accessTile(x + 1, y);
      newX = x + 1;
      newY = y;
    } else if (heading == 3) {
      tile2 = accessTile(x + 1, y + 1);
      newX = x + 1;
      newY = y + 1;
    } else if (heading == 4) {
      tile2 = accessTile(x, y + 1);
      newX = x;
      newY = y + 1;
    } else if (heading == 5) {
      tile2 = accessTile(x - 1, y + 1);
      newX = x - 1;
      newY = y + 1;
    } else if (heading == 6) {
      tile2 = accessTile(x - 1, y);
      newX = x - 1;
      newY = y;
    } else if (heading == 7) {
      tile2 = accessTile(x - 1, y - 1);
      newX = x - 1;
      newY = y - 1;
    } else {
      return false;
    } 
    if (isExistDoor(newX, newY) == 3)
      return false; 
    if ((tile2 & 0xFFFFFF80) == -128)
      return false; 
    if ((tile2 & 0x2) != 2 && (tile2 & 0x1) != 1)
      return false; 
    if (heading == 0)
      return ((tile1 & 0x2) == 2); 
    if (heading == 1) {
      int tile3 = accessTile(x, y - 1);
      int tile4 = accessTile(x + 1, y);
      return !((tile3 & 0x1) != 1 && (tile4 & 0x2) != 2);
    } 
    if (heading == 2)
      return ((tile1 & 0x1) == 1); 
    if (heading == 3) {
      int tile3 = accessTile(x, y + 1);
      return ((tile3 & 0x1) == 1);
    } 
    if (heading == 4)
      return ((tile2 & 0x2) == 2); 
    if (heading == 5)
      return !((tile2 & 0x1) != 1 && (tile2 & 0x2) != 2); 
    if (heading == 6)
      return ((tile2 & 0x1) == 1); 
    if (heading == 7) {
      int tile3 = accessTile(x - 1, y);
      return ((tile3 & 0x2) == 2);
    } 
    return false;
  }
  
  public boolean isPassable(int x, int y, int heading, L1Character cha) {
    try {
      int tile3, tile4, tile1 = accessTile(x, y);
      int locx = x + HEADING_TABLE_X[heading];
      int locy = y + HEADING_TABLE_Y[heading];
      int tile2 = accessTile(locx, locy);
      if (tile2 == 0)
        return false; 
      if ((tile2 & 0xFFFFFF80) == -128)
        return false; 
      if (cha != null) {
        switch (this._mapId) {
          case 0:
            return set_map(tile2, 1);
          case 4:
          case 57:
          case 58:
          case 68:
          case 69:
          case 70:
          case 303:
          case 430:
          case 440:
          case 445:
          case 480:
          case 613:
          case 630:
            switch (tile2) {
              case 12:
              case 21:
              case 26:
              case 28:
              case 29:
              case 44:
                return false;
            } 
            break;
        } 
        return set_map(tile2, 3);
      } 
      switch (heading) {
        case 0:
          return ((tile1 & 0x2) == 2);
        case 1:
          tile3 = accessTile(x, y - 1);
          tile4 = accessTile(x + 1, y);
          return !((tile3 & 0x1) != 1 && (tile4 & 0x2) != 2);
        case 2:
          return ((tile1 & 0x1) == 1);
        case 3:
          tile3 = accessTile(x, y + 1);
          return ((tile3 & 0x1) == 1);
        case 4:
          return ((tile2 & 0x2) == 2);
        case 5:
          return !((tile2 & 0x1) != 1 && (tile2 & 0x2) != 2);
        case 6:
          return ((tile2 & 0x1) == 1);
        case 7:
          tile3 = accessTile(x - 1, y);
          return ((tile3 & 0x2) == 2);
      } 
    } catch (Exception exception) {}
    return false;
  }
  
  public boolean isPassableDna(int x, int y, int heading) {
    try {
      int locx = x + HEADING_TABLE_X[heading];
      int locy = y + HEADING_TABLE_Y[heading];
      int tile2 = accessTile(locx, locy);
      if (tile2 == 0)
        return false; 
      switch (this._mapId) {
        case 0:
          return set_map(tile2, 1);
        case 4:
        case 57:
        case 58:
        case 68:
        case 69:
        case 70:
        case 303:
        case 430:
        case 440:
        case 445:
        case 480:
        case 613:
        case 630:
          switch (tile2) {
            case 28:
              return false;
            case 44:
              return false;
            case 21:
              return false;
            case 26:
              return false;
            case 29:
              return false;
            case 12:
              return false;
          } 
          return set_map(tile2, 8);
      } 
      return set_map(tile2, 3);
    } catch (Exception ex) {
      return false;
    } 
  }
  
  private boolean set_map(int tile2, int i) {
    return ((tile2 & i) != 0);
  }
  
  public boolean isDoorPassable(int x, int y, int heading, L1NpcInstance npc) {
    try {
      if (heading == -1)
        return false; 
      int locx = x + HEADING_TABLE_X[heading];
      int locy = y + HEADING_TABLE_Y[heading];
      int tile2 = accessTile(locx, locy);
      if (npc != null) {
        if (tile2 != 3)
          return true; 
        if (npc.is_now_target() == null)
          return false; 
        Iterator<L1Object> iterator = World.get().getVisibleObjects((L1Object)npc, 2).iterator();
        while (iterator.hasNext()) {
          L1Object object = iterator.next();
          if (object instanceof L1DoorInstance) {
            L1DoorInstance door = (L1DoorInstance)object;
            switch (door.getDoorId()) {
              case 6006:
              case 6007:
              case 10000:
              case 10001:
              case 10002:
              case 10003:
              case 10004:
              case 10005:
              case 10006:
              case 10007:
              case 10008:
              case 10009:
              case 10010:
              case 10011:
              case 10012:
              case 10013:
              case 10015:
              case 10016:
              case 10017:
              case 10019:
              case 10020:
              case 10036:
                return false;
            } 
            if (door.getOpenStatus() != 29)
              return true; 
            if (npc instanceof com.lineage.server.model.Instance.L1GuardInstance) {
              door.open();
              return true;
            } 
            if (door.getKeeperId() == 0) {
              door.open();
              return true;
            } 
          } 
        } 
        return false;
      } 
    } catch (Exception exception) {}
    return true;
  }
  
  public void setPassable(Point pt, boolean isPassable) {
    setPassable(pt.getX(), pt.getY(), isPassable, 2);
  }
  
  public void setPassable(int x, int y, boolean isPassable, int door) {
    switch (door) {
      case 0:
        set_door_0(x, y, isPassable);
        return;
      case 1:
        set_door_1(x, y, isPassable);
        return;
    } 
    if (isPassable) {
      setTile(x, y, (short)(accessTile(x, y) & 0x7F));
    } else {
      setTile(x, y, (short)(accessTile(x, y) | 0xFFFFFF80));
    } 
  }
  
  private void set_door_0(int x, int y, boolean isPassable) {
    try {
      if (isPassable) {
        this._map[x - this._worldTopLeftX][y - this._worldTopLeftY] = 47;
      } else {
        this._map[x - this._worldTopLeftX][y - this._worldTopLeftY] = 3;
        this._map[x - 1 - this._worldTopLeftX][y - this._worldTopLeftY] = 3;
        this._map[x + 1 - this._worldTopLeftX][y - this._worldTopLeftY] = 3;
      } 
    } catch (Exception e) {
      _log.error("X:" + x + " Y:" + y + " MAP:" + this._mapId, e);
    } 
  }
  
  private void set_door_1(int x, int y, boolean isPassable) {
    try {
      if (isPassable) {
        this._map[x - this._worldTopLeftX][y - this._worldTopLeftY] = 47;
      } else {
        this._map[x - this._worldTopLeftX][y - this._worldTopLeftY] = 3;
        this._map[x - this._worldTopLeftX][y - 1 - this._worldTopLeftY] = 3;
        this._map[x - this._worldTopLeftX][y + 1 - this._worldTopLeftY] = 3;
      } 
    } catch (Exception e) {
      _log.error("X:" + x + " Y:" + y + " MAP:" + this._mapId, e);
    } 
  }
  
  public boolean isSafetyZone(Point pt) {
    return isSafetyZone(pt.getX(), pt.getY());
  }
  
  public boolean isSafetyZone(int x, int y) {
    int tile = accessOriginalTile(x, y);
    return ((tile & 0x30) == 16);
  }
  
  public boolean isCombatZone(Point pt) {
    return isCombatZone(pt.getX(), pt.getY());
  }
  
  public boolean isCombatZone(int x, int y) {
    int tile = accessOriginalTile(x, y);
    return ((tile & 0x30) == 32);
  }
  
  public boolean isNormalZone(Point pt) {
    return isNormalZone(pt.getX(), pt.getY());
  }
  
  public boolean isNormalZone(int x, int y) {
    int tile = accessOriginalTile(x, y);
    return ((tile & 0x30) == 0);
  }
  
  public boolean isArrowPassable(Point pt) {
    return isArrowPassable(pt.getX(), pt.getY());
  }
  
  public boolean isArrowPassable(int x, int y) {
    return ((accessOriginalTile(x, y) & 0xE) != 0);
  }
  
  public boolean isArrowPassable(Point pt, int heading) {
    return isArrowPassable(pt.getX(), pt.getY(), heading);
  }
  
  public boolean isArrowPassable(int x, int y, int heading) {
    try {
      int newX = x + HEADING_TABLE_X[heading];
      int newY = y + HEADING_TABLE_Y[heading];
      int tile2 = accessTile(newX, newY);
      switch (tile2) {
        case 0:
        case 3:
          return false;
      } 
      return ((tile2 & 0xC) != 0);
    } catch (Exception ex) {
      return false;
    } 
  }
  
  public boolean isUnderwater() {
    return this._isUnderwater;
  }
  
  public boolean isMarkable() {
    return this._isMarkable;
  }
  
  public boolean isTeleportable() {
    return this._isTeleportable;
  }
  
  public boolean isEscapable() {
    return this._isEscapable;
  }
  
  public boolean isUseResurrection() {
    return this._isUseResurrection;
  }
  
  public boolean isUsePainwand() {
    return this._isUsePainwand;
  }
  
  public boolean isEnabledDeathPenalty() {
    return this._isEnabledDeathPenalty;
  }
  
  public boolean isTakePets() {
    return this._isTakePets;
  }
  
  public boolean isRecallPets() {
    return this._isRecallPets;
  }
  
  public boolean isUsableItem() {
    return this._isUsableItem;
  }
  
  public boolean isUsableSkill() {
    return this._isUsableSkill;
  }
  
  public boolean isGuaji() {
    return this._isGuaji;
  }
  
  public boolean isClanPc() {
    return this._isClanPc;
  }
  
  public boolean isPartyPc() {
    return this._isPartyPc;
  }
  
  public boolean isAlliancePc() {
    return this._isAlliancePc;
  }
  
  public int isUsableShop() {
    return this._isUsableShop;
  }
  
  public int isStart_time() {
    return this._isStart_time;
  }
  
  public int isweek() {
    return this._isweek;
  }
  
  public int isEnd_time() {
    return this._isEnd_time;
  }
  
  public boolean isdropitem() {
    return this._isdropitem;
  }
  
  public boolean isFishingZone(int x, int y) {
    return (accessOriginalTile(x, y) == 28);
  }
  
  public int isExistDoor(int x, int y) {
    try {
      return this._map[x - this._worldTopLeftX][y - this._worldTopLeftY];
    } catch (Exception ex) {
      return 0;
    } 
  }
  
  public String toString(Point pt) {
    return ""+getOriginalTile(pt.getX(), pt.getY());
  }
  
  public L1V1Map copyMap(int newMapId) {
    return clone(newMapId);
  }
  
  private L1V1Map clone(int newMapId) {
    L1V1Map map = new L1V1Map(this);
    map._mapId = newMapId;
    map._isUnderwater = this._isUnderwater;
    map._isMarkable = this._isMarkable;
    map._isTeleportable = this._isTeleportable;
    map._isEscapable = this._isEscapable;
    map._isUseResurrection = this._isUseResurrection;
    map._isUsePainwand = this._isUsePainwand;
    map._isEnabledDeathPenalty = this._isEnabledDeathPenalty;
    map._isTakePets = this._isTakePets;
    map._isRecallPets = this._isRecallPets;
    map._isUsableItem = this._isUsableItem;
    map._isUsableSkill = this._isUsableSkill;
    map._isGuaji = this._isGuaji;
    map._isdropitem = this._isdropitem;
    return map;
  }
  
  public void setPassable(int x, int y, boolean isPassable) {}
}
